package com.tinckay.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.BeanProperty;
import com.tinckay.common.constant.AmqpConstant;
import com.tinckay.common.constant.RedisConstant;
import com.tinckay.common.exception.ServiceException;
import com.tinckay.entity.po.PumpWarnLevel;
import com.tinckay.mapper.PumpWarnLevelMapper;
import com.tinckay.service.PumpWarnLevelService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 泵车监测预警阀值 服务实现类
 * </p>
 *
 * @author Jean
 * @since 2018-11-10
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class PumpWarnLevelServiceImpl extends ServiceImpl<PumpWarnLevelMapper, PumpWarnLevel> implements PumpWarnLevelService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(PumpWarnLevel pumpWarnLevel) {
        int rows = super.count(new QueryWrapper<PumpWarnLevel>().lambda().eq(PumpWarnLevel::getPumpCode, pumpWarnLevel.getPumpCode()));
        if (rows > 0) {
            throw new ServiceException("该泵车已有绑定预警阀值");
        }
        boolean result = super.save(pumpWarnLevel);
        cacheAndSendMsg();
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(PumpWarnLevel pumpWarnLevel) {
        boolean result = super.updateById(pumpWarnLevel);
        cacheAndSendMsg();
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByPumpCode(String pumpCode) {
        LambdaQueryWrapper<PumpWarnLevel> wrapper = new QueryWrapper<PumpWarnLevel>().lambda().eq(PumpWarnLevel::getPumpCode, pumpCode);
        redisTemplate.opsForHash().delete(RedisConstant.PUMP_WARN_LEVEL_MAP, pumpCode);
        sendMsg();
        return super.remove(wrapper);
    }

    private void cacheAndSendMsg() {
        List<PumpWarnLevel> cacheList = list(null);
        Map<String, com.tinckay.common.object.PumpWarnLevel> cacheMap = buildPumpWarnLevel(cacheList);
        redisTemplate.delete(RedisConstant.PUMP_WARN_LEVEL_MAP);
        redisTemplate.opsForHash().putAll(RedisConstant.PUMP_WARN_LEVEL_MAP, cacheMap);
        sendMsg();
    }

    private void sendMsg() {
        rabbitTemplate.convertAndSend(
                AmqpConstant.REDIS_CHANGE_FANOUT_EXCHANGE,
                null,
                RedisConstant.PUMP_WARN_LEVEL_MAP,
                new CorrelationData(RandomUtil.simpleUUID())
        );
    }

    private Map<String, com.tinckay.common.object.PumpWarnLevel> buildPumpWarnLevel(List<PumpWarnLevel> cacheList) {
        Map<String, com.tinckay.common.object.PumpWarnLevel> cacheMap = cacheList.parallelStream().map(pumpWarnLevel -> {
            com.tinckay.common.object.PumpWarnLevel target = new com.tinckay.common.object.PumpWarnLevel();
            BeanUtil.copyProperties(pumpWarnLevel, target);
            return target;
        }).collect(Collectors.toMap(com.tinckay.common.object.PumpWarnLevel::getPumpCode, Function.identity()));
        return cacheMap;
    }

}
